﻿///////////////////////////////////////////////////////////////////////////////
// File:        Connection.cc
// Author:      671643387@qq.com
// Description:
///////////////////////////////////////////////////////////////////////////////

#include "nio/net/Connection.hpp"
using namespace nio::net;

Connection::Connection(sock_t sock, unsigned int isSize, unsigned int osSize)
    : id_(-1)
    , state_(NORMAL)
    , userIO_(false)
    , sock_(sock)
    , is_(sock_, isSize)
    , os_(sock_, osSize)
    , readableFN_()
    , writableFN_()
    , errorFN_()
    , heartbeatFN_()
    , closeFN_()
    , userPointer_(NULL)
{

}

Connection::Connection(sock_t sock, ByteBuffer isBuff,
    unsigned int isSize, ByteBuffer osBuff, unsigned int osSize)
    : id_(-1)
    , state_(NORMAL)
    , userIO_(false)
    , sock_(sock)
    , is_(sock_, isBuff, isSize)
    , os_(sock_, osBuff, osSize)
    , readableFN_()
    , writableFN_()
    , errorFN_()
    , heartbeatFN_()
    , closeFN_()
    , userPointer_(NULL)
{

}

Connection::~Connection()
{

}

bool Connection::setSendBufferSize(unsigned int size)
{
    return sock_.setOption(SOL_SOCKET, SO_SNDBUF, (const char*)&size, sizeof(size));
}

bool Connection::setRecvBufferSize(unsigned int size)
{
    return sock_.setOption(SOL_SOCKET, SO_RCVBUF, (const char*)&size, sizeof(size));
}

void Connection::shutdown()
{
    assert(state_ == NORMAL && shutdownFN_);
    setState(EXITING);
    shutdownFN_(this);
}

void Connection::handleInput()
{
    assert(readableFN_);
    if (state_ != NORMAL)
        return;

    if (!userIO_)
    {
        int bytsRead = is_.fill();
        if (bytsRead == SOCKET_ERROR)
        {
            errorFN_(*this);
            shutdown();
            return;
        }

        if (is_.size() > 0)
            readableFN_(*this, is_);
    }
    else
    {
        readableFN_(*this, is_);
    }
}

void Connection::handleOutput()
{
    assert(writableFN_);
    if (state_ != NORMAL)
        return;

    if (!userIO_)
    {
        int bytsWrite = os_.flush();
        if (bytsWrite == SOCKET_ERROR)
        {
            errorFN_(*this);
            shutdown();
            return;
        }

        if (os_.space() > 0)
            writableFN_(*this, os_);
    }
    else
    {
        writableFN_(*this, os_);
    }
}

void Connection::handleError()
{
    assert(errorFN_);
    if (state_ != NORMAL)
        return;
    errorFN_(*this);
    shutdown();
}

void Connection::handleHeartbeat()
{
    assert(heartbeatFN_);
    if (state_ != NORMAL)
        return;
    heartbeatFN_(*this);
}
